package com.lingjtx.oss.controller;

import com.lingjtx.common.core.algorithm.Base64Util;
import com.lingjtx.common.core.util.StringUtil;
import com.lingjtx.oss.common.RegionPositions;
import io.minio.GetObjectArgs;
import io.minio.MinioClient;
import io.minio.errors.*;
import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.geometry.Positions;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import reactor.core.publisher.Mono;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

@Controller
@RequestMapping("/image")
public class MinioImageProcessController {

    @Value("${minio.bucket}")
    private String bucketName;

    private final MinioClient minioClient;

    public MinioImageProcessController(MinioClient minioClient) {
        this.minioClient = minioClient;
    }

    @GetMapping(value = "/{objectName}", produces = MediaType.IMAGE_JPEG_VALUE)
    public Mono<Void> imageProcess(@PathVariable String objectName,
                                   @RequestParam(name = "w", defaultValue = "0") int width,
                                   @RequestParam(name = "h", defaultValue = "0") int height,
                                   @RequestParam(name = "q", defaultValue = "1") float quality,
                                   @RequestParam(name = "r", defaultValue = "0") float rotate,
                                   @RequestParam(name = "s", defaultValue = "1") float scale,
                                   String region,
                                   String watermark,
                                   ServerHttpResponse response) {
        return Mono.fromCallable(() -> {
                    try (InputStream is = getInputStream(objectName);
                         ByteArrayOutputStream baos = new ByteArrayOutputStream()) {

                        Thumbnails.Builder<BufferedImage> builder = builderThumbnails(is);
                        setSize(builder, width, height);
                        setWatermark(builder, watermark);
                        setRegion(builder, region);
                        setOther(builder, quality, rotate, scale);
                        builder.toOutputStream(baos);

                        return wrap(baos, response);
                    }
                }).flatMap(buffer -> response.writeWith(Mono.just(buffer)))
                .onErrorResume(e -> {
                    response.setStatusCode(HttpStatus.BAD_REQUEST);
                    byte[] errBytes = ("Image processing failed: " + e.getMessage()).getBytes(StandardCharsets.UTF_8);
                    return response.writeWith(Mono.just(response.bufferFactory().wrap(errBytes)));
                });
    }

    public InputStream getInputStream(String objectName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        String uri = Base64Util.decode(objectName);
        GetObjectArgs args = GetObjectArgs.builder().bucket(bucketName).object(uri).build();
        return minioClient.getObject(args);
    }

    public Thumbnails.Builder<BufferedImage> builderThumbnails(InputStream is) throws IOException {
        BufferedImage sourceImage = ImageIO.read(is);
        if (sourceImage == null) {
            throw new IllegalArgumentException("Unable to read the image (unsupported format)");
        }
        return Thumbnails.of(sourceImage);
    }

    public DataBuffer wrap(ByteArrayOutputStream baos, ServerHttpResponse response) {
        byte[] imageBytes = baos.toByteArray();
        response.getHeaders().setContentType(MediaType.IMAGE_JPEG);
        response.getHeaders().setContentLength(imageBytes.length);
        return response.bufferFactory().wrap(imageBytes);
    }

    public void setSize(Thumbnails.Builder<BufferedImage> builder, int width, int height) {
        if (width > 0 && height > 0) {
            builder.size(width, height);
        }
    }

    public void setWatermark(Thumbnails.Builder<BufferedImage> builder, String watermark) {
        if (StringUtil.isNotEmpty(watermark)) {
            BufferedImage watermarkImage = createTextWatermark(watermark);
            builder.watermark(Positions.BOTTOM_RIGHT, watermarkImage, 0.8f); // 位置 + 透明度
        }
    }

    public void setRegion(Thumbnails.Builder<BufferedImage> builder, String region) {
        if (StringUtil.isNotEmpty(region)) { // c,200,300
            String[] arr = region.split(",");
            if (arr.length == 3) {
                RegionPositions positions = RegionPositions.of(arr[0]);
                builder.sourceRegion(positions.getPos(), Integer.parseInt(arr[1]), Integer.parseInt(arr[2]));
            }
        }
    }

    public void setOther(Thumbnails.Builder<BufferedImage> builder,
                         float quality,
                         float rotate,
                         float scale) {
        builder.outputFormat("jpeg")
                .outputQuality(quality)
                .rotate(rotate)
                .scale(scale);
    }

    public BufferedImage createTextWatermark(String text) {
        Font font = new Font("微软雅黑", Font.PLAIN, 16);
        Color color = new Color(255, 255, 255, 255); // 白色不透明

        // 先创建一个临时图像以获取 FontMetrics
        BufferedImage tempImg = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2dTemp = tempImg.createGraphics();
        g2dTemp.setFont(font);
        FontMetrics fm = g2dTemp.getFontMetrics();
        int textWidth = fm.stringWidth(text);
        int textHeight = fm.getHeight();
        g2dTemp.dispose();

        // 添加 padding
        int paddingX = 10;
        int paddingY = 5;
        int width = textWidth + paddingX * 2;
        int height = textHeight + paddingY * 2;

        // 创建实际图片
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2d = image.createGraphics();

        // 背景透明
        g2d.setComposite(AlphaComposite.Clear);
        g2d.fillRect(0, 0, width, height);

        // 设置文字
        g2d.setComposite(AlphaComposite.SrcOver);
        g2d.setColor(color);
        g2d.setFont(font);

        // 绘制文字（加上 padding 偏移）
        int y = paddingY + fm.getAscent();
        g2d.drawString(text, paddingX, y);
        g2d.dispose();

        return image;
    }
}
